<?php

namespace Remoteshell\PhpBotSdk\loader;

use ReflectionClass;
use ReflectionException;
use Remoteshell\PhpBotSdk\announce\Version;
use Remoteshell\PhpBotSdk\logger\STDLoggerOut;

/**
 * 组件注入器
 * 代替传统的插件加载器，原因是因为在CLI环境下如何触发事是个问题
 * 所以将设计这个加载器，把组建注入进index.php下
 * @Class ComponentsInjector
 * @Jason 2025.2.23
 */
class ComponentsInjector extends ComponentsRegister implements Version
{
    private STDLoggerOut $logger;
    private array $struct = [];
    private array $classes;

    /**
     * @constructor method
     */
    public function __construct()
    {
        spl_autoload_register(function ($className) {
            $file = $this->getClassFilePath($className);
            if (file_exists($file)) {
                require_once $file;
            }
        });
        $this->logger = new STDLoggerOut();
    }

    /**
     * 解析组件信息
     * @param string $components_path
     * @return void
     * @throws ReflectionException
     */
    public function parseComponentsInfo(string $components_path): void
    {
        // 判断是否为目录
        if (is_dir($components_path)) {
            // 如果是目录就打开文件夹
            if ($handle = opendir($components_path)) {
                while (($entry = readdir($handle)) !== false) {
                    if ($entry != "." && $entry != "..") {
                        $fullPath = $components_path . DIRECTORY_SEPARATOR . $entry;
                        if (is_dir($fullPath)) {
                            $this->parseComponentsInfo($fullPath);
                        } else {
                            $end = pathinfo($fullPath, PATHINFO_EXTENSION);
                            if ($end == "json"){
                                $json = json_decode(file_get_contents($fullPath), true);
                                $api_version = $json['api'];
                                $name = $json['name'];
                                $version = $json['version'];
                                $base = $json['base'];
                                $namespace = $json['namespace'] . "\\". "src";
                                $injector_point = $json['injector_point'];
                                $this->struct[] = [
                                    "main_class" => $namespace . "\\" . $base,
                                    "base" => $base,
                                    "name" => $name,
                                    "path" => $injector_point
                                ];

                                $this->MainInjector($this->struct);
                                if ($api_version !== self::API){
                                    $this->logger->record(
                                        "error",
                                        "不受支持的组件API版本！请检查插件: " . $name
                                    );
                                }
                                $this->logger->record("normal", "[ $name ]" . "插件 [$name] 加载成功！版本：" . $version);
                            }
                        }
                    }
                }
                closedir($handle);
            }
        } else {
            echo "[$components_path] is not a directory!\n";
        }
    }

    /**
     * 注入类到index
     * @param array $params
     * @throws ReflectionException
     */
    public function MainInjector(array $params): void
    {
        // 检测基类
        if (isset($params[0]['main_class'])) {
            $mainClass = $params[0]['main_class'];
            $classFile = $this->getClassFilePath($mainClass);
            $base = $params[0]['base'];

            if (file_exists($classFile)) {
                require_once $classFile; // 使用 require_once 避免重复包含
            } else {
                $this->logger->record("error", "组件" . $params[0]['name'] . "错误！" . "类文件不存在：" . $classFile);
                return;
            }

            if (!class_exists($mainClass)) {
                $this->logger->record("error", "组件" . $params[0]['name'] . "错误！" . "类未定义：" . $mainClass);
                return;
            }

            $reflection = new ReflectionClass($mainClass);
            if (!$reflection->isSubclassOf(STD::class)) {
                $this->logger->record("error", "组件" . $params[0]['name'] . "错误！" . "没有对组件进行注册！");
            }
            $methods = $reflection->getMethods();
            $foundInitMethod = false;
            foreach ($methods as $method) {
                if ($method->getName() === "__init__") {
                    $foundInitMethod = true;
                    $instance = $reflection->newInstance();
                    $method->invoke($instance);
                    $this->BuiltRouteMap($this->struct, $params[0]['path']);
                    $this->logger->record("normal", "组件" . $params[0]['name'] . "实例化成功！");
                    break;
                }
            }
            if (!$foundInitMethod) {
                $this->logger->record("error", "组件" . $params[0]['name'] . "错误！" . "没有实例化方法！！");
            }
        } else {
            $this->logger->record("error", "组件" . $params[0]['name'] . "致命错误！" . "缺失重要字段！！！");
        }
    }

    /**
     * 获取类文件路径
     * @param string $className
     * @return string
     */
    private function getClassFilePath(string $className): string
    {
        $baseDir = '../public/' .  "components/" ; // 根据实际情况调整基础目录
        $relativePath = str_replace('\\', '/', $className) . '.php';
        return $baseDir . $relativePath;
    }

    /**
     * 构造路由
     * @param array $params
     * @param string $components_list_path
     * @return void
     */
    private function BuiltRouteMap(array $params, string $components_list_path): void
    {
        file_put_contents($components_list_path, json_encode($params, JSON_PRETTY_PRINT));
    }

    /**
     * 获取某个命名空间下所有类，用于构建路由
     * @param string $namespace
     * @return void
     * @throws ReflectionException
     */
    public function GetAllClassesFromNameSpace(string $namespace): void
    {
        $this->classes = [];
        foreach (get_declared_classes() as $class) {
            $r = new \ReflectionClass($class);
            if ($r->getNamespaceName() === $namespace) {
               $this->classes[] = $class;
            }
        }
    }

    // TODO! 自动分配路由
}
